// Copyright (c) 2011 Blue Onion Software, All rights reserved
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Web.UI;
using System.Web.UI.WebControls;
using BlueOnionSoftware.Bloget.Properties;

namespace BlueOnionSoftware.Bloget
{
    internal class EditView : View
    {
        private readonly TextBox _title = new TextBox();
        private readonly TextBox _text = new TextBox();
        private readonly CheckBox _draft = new CheckBox();
        private readonly CheckBox _syndicate = new CheckBox();
        private readonly CheckBox _enableComments = new CheckBox();
        private readonly FileUpload _imageUpload = new FileUpload();
        private readonly FileUpload _fileUpload = new FileUpload();
        private readonly FileUpload _enclosureUpload = new FileUpload();
        private readonly CheckBox _enclosureName = new CheckBox();
        private readonly TextBox _newCategory = new TextBox();
        private readonly CheckBoxList _categoryList = new CheckBoxList();

        private bool _disposed;
        private const int MaxPasswordLength = 30;
        private const int MaxTextBoxLength = 200;

        private enum PostType
        {
            None,
            NewPost,
            EditPost
        } ;

        internal EditView(Bloget blogetArg)
            : base(blogetArg)
        {
            _title.ID = "title";
            _text.ID = "text";
            _draft.ID = "draft";
            _syndicate.ID = "syndicate";
            _enableComments.ID = "enableComments";
            _imageUpload.ID = "imageUpload";
            _fileUpload.ID = "fileUpload";
            _enclosureUpload.ID = "enclosureUpload";
            _enclosureName.ID = "enclosureName";
            _newCategory.ID = "newCategory";
            _categoryList.ID = "categoryList";

            if (Bloget.Page.Header != null)
            {
                const string wysiwygScript = "BlueOnionSoftware.Bloget.Resources.Openwysiwyg.wysiwyg.js";

                if (Bloget.Page.ClientScript.IsClientScriptBlockRegistered(wysiwygScript) == false)
                {
                    // Tip from the code project. Register an empty script to get the benifits of registered
                    // scripts using an empty string. Then add the real script to the header section.
                    Bloget.Page.ClientScript.RegisterClientScriptBlock(GetType(), wysiwygScript, string.Empty);

                    Bloget.Page.Header.Controls.Add(new LiteralControl(
                                                        string.Format(CultureInfo.InvariantCulture,
                                                                      "{0}<script type=\"text/javascript\" src=\"{1}\"></script>{2}",
                                                                      Environment.NewLine,
                                                                      Bloget.Page.ClientScript.GetWebResourceUrl(GetType(), wysiwygScript),
                                                                      Environment.NewLine)));
                }
            }
        }

        protected override void Dispose(bool managed)
        {
            try
            {
                if (_disposed == false)
                {
                    _disposed = true;

                    if (managed)
                    {
                        _title.Dispose();
                        _text.Dispose();
                        _draft.Dispose();
                        _syndicate.Dispose();
                        _enableComments.Dispose();
                        _imageUpload.Dispose();
                        _fileUpload.Dispose();
                        _enclosureUpload.Dispose();
                        _enclosureName.Dispose();
                        _newCategory.Dispose();
                        _categoryList.Dispose();
                    }
                }
            }

            finally
            {
                base.Dispose(managed);
            }
        }

        protected override string RootClassId()
        {
            return "edit-view";
        }

        [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        protected override void ShowView()
        {
            if (Bloget.IsAuthorOrAdministrator == false)
            {
                var passwordForm = new PasswordView(Bloget);
                passwordForm.Show();
                return;
            }

            MainMenu.ShowMenu(Bloget);

            const int buttonWidth = 8;
            var post = new Post();
            var content = new Content();
            var postId = Bloget.QueryPost;

            if (string.IsNullOrEmpty(postId) == false)
            {
                try
                {
                    var id = new Guid(postId);
                    post = Bloget.Blog.Posts[id];
                    content = Bloget.Blog.LoadContent(id);
                }

                catch (Exception)
                {
                    Bloget.Write("<p>");

                    Bloget.Write(string.Format(CultureInfo.InvariantCulture,
                                               Resources.EditViewInvalidPostParameter,
                                               Bloget.BlogPostParameter));

                    Bloget.WriteLine("</p>");
                    return;
                }
            }

            // Title
            Bloget.Write("<p>");
            Bloget.Write(Resources.EditViewTitle);
            var rfv = new RequiredFieldValidator
            {
                ControlToValidate = _title.ID,
                Text = " *"
            };
            Bloget.Controls.Add(rfv);

            Bloget.WriteLine(Environment.NewLine);
            _title.Style.Add(HtmlTextWriterStyle.Width, "70%");
            _title.Style.Add(HtmlTextWriterStyle.FontWeight, "bold");
            _title.MaxLength = MaxTextBoxLength;
            _title.Text = Bloget.Page.Server.HtmlDecode(post.Title);
            Bloget.Controls.Add(_title);
            Bloget.WriteLine("</p>");

            // Textbox
            Bloget.WriteLine("<p>");
            _text.TextMode = TextBoxMode.MultiLine;
            _text.Text = content.Text;
            _text.Width = new Unit(99, UnitType.Percentage);
            Bloget.Controls.Add(_text);

            Bloget.WriteLine("<script>generate_wysiwyg2('" + _text.ClientID + "'," +
                Bloget.Blog.EditorWidth + "," + Bloget.Blog.EditorHeight + ")</script>");

            Bloget.WriteLine("</p>");

            Bloget.WriteLine("<p>");
            _draft.Text = Resources.EditViewDraft;
            _draft.Checked = post.Draft;
            Bloget.Controls.Add(_draft);

            Bloget.WriteLine("&nbsp;");

            // Syndicate checkbox
            _syndicate.Text = Resources.EditViewSyndicate;
            _syndicate.Checked = post.Syndicate;
            Bloget.Controls.Add(_syndicate);

            Bloget.WriteLine("&nbsp;");

            // Allow comments checkbox
            _enableComments.Text = Resources.EditAllowCommentsButton;
            _enableComments.Checked = post.EnableComments;
            Bloget.Controls.Add(_enableComments);
            Bloget.WriteLine("</p>");

            var table = new Table();
            Bloget.Controls.Add(table);

            // Add Image
            var row = new TableRow();
            table.Rows.Add(row);
            var cell = new TableCell();
            cell.Controls.Add(new LiteralControl(Resources.EditViewAddImage));
            row.Cells.Add(cell);
            cell = new TableCell();
            cell.Controls.Add(_imageUpload);
            row.Cells.Add(cell);
            var addImage = new Button
            {
                Text = "Add Image",
                Width = new Unit(buttonWidth, UnitType.Em)
            };
            addImage.Click += UploadImageClick;
            cell = new TableCell();
            cell.Controls.Add(addImage);
            row.Cells.Add(cell);

            // Add File
            row = new TableRow();
            table.Rows.Add(row);
            cell = new TableCell();
            cell.Controls.Add(new LiteralControl(Resources.EditViewAddFile));
            row.Cells.Add(cell);
            cell = new TableCell();
            cell.Controls.Add(_fileUpload);
            row.Cells.Add(cell);
            var uploadFile = new Button
            {
                Text = "Upload File",
                Width = new Unit(buttonWidth, UnitType.Em)
            };
            uploadFile.Click += UploadFileClick;
            cell = new TableCell();
            cell.Controls.Add(uploadFile);
            row.Cells.Add(cell);

            // Enclosure
            row = new TableRow();
            table.Rows.Add(row);
            cell = new TableCell();
            cell.Controls.Add(new LiteralControl(Resources.EditViewRssEnclosure));
            cell.Controls.Add(new LiteralControl("&nbsp;"));
            row.Cells.Add(cell);

            cell = new TableCell();

            if (content.Attachments.Count > 0)
            {
                _enclosureName.Text = content.Attachments[0].Name;
                _enclosureName.Checked = true;
                cell.Controls.Add(_enclosureName);
            }

            else
            {
                _enclosureName.Visible = false;
            }

            _enclosureUpload.Visible = (content.Attachments.Count == 0);
            cell.Controls.Add(_enclosureUpload);
            row.Cells.Add(cell);

            // New Category
            row = new TableRow();
            table.Rows.Add(row);
            cell = new TableCell();
            cell.Controls.Add(new LiteralControl(Resources.EditViewNewCategory));
            cell.Controls.Add(new LiteralControl("&nbsp;"));
            row.Cells.Add(cell);
            _newCategory.MaxLength = MaxPasswordLength;
            cell = new TableCell();
            cell.Controls.Add(_newCategory);
            row.Cells.Add(cell);

            var categoryValidator = new RegularExpressionValidator {ControlToValidate = _newCategory.ID};
            const string categoryValidatorExpression = "[a-zA-Z0-9.& ]*";
            categoryValidator.ValidationExpression = categoryValidatorExpression;
            categoryValidator.Text = categoryValidatorExpression;
            cell = new TableCell();
            cell.Controls.Add(categoryValidator);
            row.Cells.Add(cell);

            // Category checkbox list
            if (Bloget.Blog.Categories.Count != 0)
            {
                _categoryList.RepeatDirection = RepeatDirection.Horizontal;
                _categoryList.RepeatColumns = 5;

                foreach (var category in Bloget.Blog.Categories.Sorted())
                {
                    var listItem = new ListItem
                    {
                        Text = category.Name,
                        Selected = post.HasCategory(category),
                        Value = category.Id.ToString(CultureInfo.CurrentCulture)
                    };
                    _categoryList.Items.Add(listItem);
                }

                Bloget.Controls.Add(_categoryList);
            }

            // Post button
            Bloget.WriteLine("<p>");
            var submit = new Button {Text = "          " + Resources.EditViewPost + "         ", ID = "save"};
            submit.Click += SavePostClick;
            // Ensure OpenWysiwyg is in html mode
            submit.OnClientClick = "if (viewTextMode == 1) viewText('" + _text.ClientID + "');";
            Bloget.Controls.Add(submit);
            Bloget.WriteLine(string.Empty);

            Bloget.WriteLine("&nbsp;");

            // Cancel button
            var cancel = new ConfirmedButton {Text = Resources.EditViewCancel};
            cancel.Style.Add("color", "red");
            cancel.ID = "cancel";
            cancel.Message = Resources.EditViewConfirmCancel;
            cancel.CausesValidation = false;

            cancel.Click +=
                delegate { Bloget.Redirect(Bloget.BuildQueryString(Mode.Blog, null, 0, null, null, DateTime.MinValue, null)); };

            Bloget.Controls.Add(cancel);
            Bloget.WriteLine(string.Empty);

            // Remove button
            if (string.IsNullOrEmpty(postId) == false)
            {
                Bloget.WriteLine("&nbsp;");

                var remove = new ConfirmedButton {Text = Resources.EditViewRemove};
                remove.Style.Add("color", "red");
                remove.Message = Resources.EditViewConfirmRemove;
                remove.CausesValidation = false;
                remove.Click += RemovePostClick;
                Bloget.Controls.Add(remove);
            }

            Bloget.WriteLine("</p>");
            Bloget.Load += OnLoad;
        }

        private void OnLoad(object sender, EventArgs ea)
        {
            if (string.IsNullOrEmpty(Bloget.Page.Request[Bloget.BlogPostParameter]))
            {
                _title.Focus();
            }

            Bloget.Load -= OnLoad;
        }

        [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private void SavePostClick(object sender, EventArgs ea)
        {
            if (Bloget.Page.IsValid == false)
            {
                return;
            }

            var blog = new Blog(Bloget.Blog); // copy to protect readers
            var post = new Post();
            var content = new Content();
            var postId = Bloget.Page.Request[Bloget.BlogPostParameter];

            if (string.IsNullOrEmpty(postId) == false)
            {
                try
                {
                    var id = new Guid(postId);
                    post = blog.Posts[id];
                    content = blog.LoadContent(id);
                    content = new Content(content); // Clone to protect readers
                }

                catch
                {
                    Bloget.WriteLine("<p>Invalid post identifier</p>");
                    return;
                }
            }

            post.Title = Bloget.Page.Server.HtmlEncode(_title.Text);
            post.Author = Bloget.GetUser().UserName;
            content.Text = _text.Text;

            // Check for attachment
            if (_enclosureUpload != null)
            {
                if (_enclosureUpload.HasFile)
                {
                    var path = Bloget.Page.MapPath(blog.ImageFolder);
                    path = Path.Combine(path, _enclosureUpload.FileName);
                    _enclosureUpload.SaveAs(path);
                    var attachment = new Attachment
                    {
                        Url = blog.ImageFolder + _enclosureUpload.FileName,
                        MimeType = _enclosureUpload.PostedFile.ContentType,
                        Length = _enclosureUpload.PostedFile.ContentLength,
                        AttachmentType = "Enclosure"
                    };
                    content.Attachments.Clear(); // allow only one attachment for now
                    content.Attachments.Add(attachment);
                }
            }

            if (_enclosureName.Visible && _enclosureName.Checked == false)
            {
                content.Attachments.Clear();
            }

            blog.SaveContent(post.Id, content);

            var wasDraft = post.Draft;
            post.Draft = _draft.Checked;

            post.Syndicate = _syndicate.Checked;

            post.EnableComments = _enableComments.Checked;

            // Check existing categores
            if (_categoryList != null)
            {
                foreach (ListItem listItem in _categoryList.Items)
                {
                    var category = Bloget.Blog.Categories[int.Parse(listItem.Value, CultureInfo.CurrentCulture)];

                    if (listItem.Selected)
                    {
                        post.AddCategory(category);
                    }

                    else if (post.HasCategory(category))
                    {
                        post.RemoveCategory(category);
                    }
                }
            }

            // Check for new category
            if (string.IsNullOrEmpty(_newCategory.Text) == false)
            {
                var category = blog.Categories.CreateCategory(_newCategory.Text);
                post.AddCategory(category);
            }

            PostType postType;

            // New ml_post check
            if (string.IsNullOrEmpty(postId))
            {
                postType = PostType.NewPost;
                blog.Posts.Insert(0, post);
            }

            else
            {
                postType = PostType.EditPost;

                if (wasDraft && post.Draft == false)
                {
                    if (blog.Posts.Contains(post))
                    {
                        blog.Posts.Remove(post);
                        blog.Posts.Insert(0, post);
                    }
                }
            }

            blog.Save();

            switch (postType)
            {
                case PostType.NewPost:
                    Log.NewPost(Bloget, post.Id, post.Title);
                    break;

                case PostType.EditPost:
                    Log.EditPost(Bloget, post.Id, post.Title);
                    break;

                default:
                    break;
            }

            if (blog.EnableAutoPingBack && post.Draft == false)
            {
                PingBackClient.PingLinks(Bloget, Bloget.PermaLink(post), content.Text);
            }

            var query = Bloget.BuildQueryString(Mode.Post, post, 0, null, null, DateTime.MinValue, null);
            Bloget.Redirect(query);
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private void RemovePostClick(object sender, EventArgs ea)
        {
            var postId = Bloget.Page.Request[Bloget.BlogPostParameter];

            if (string.IsNullOrEmpty(postId) == false)
            {
                Guid id;

                try
                {
                    id = new Guid(postId);
                }

                catch
                {
                    Bloget.WriteLine("<p>");
                    Bloget.WriteLine(Resources.EditViewRemovePostError);
                    Bloget.WriteLine("</p>");
                    return;
                }

                var blog = new Blog(Bloget.Blog); // copy to protect readers
                blog.Posts.Remove(id);
                blog.Save();
                Log.RemovePost(Bloget, id);
                Bloget.Redirect(Bloget.BuildQueryString(Mode.Blog, null, 0, null, null, DateTime.MinValue, null));
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private void UploadImageClick(object sender, EventArgs ea)
        {
            try
            {
                if (_imageUpload.HasFile)
                {
                    var path = Bloget.Page.MapPath(Bloget.Blog.ImageFolder);
                    path = Path.Combine(path, _imageUpload.FileName);
                    _imageUpload.SaveAs(path);

                    var imageLink =
                        string.Format(CultureInfo.CurrentCulture, @"<img border=""0"" src=""{0}"" />",
                                      Bloget.Blog.ImageUrl + _imageUpload.FileName);
                    _text.Text += imageLink;
                }
            }

            catch (Exception ex)
            {
                Log.Exception(Bloget, "UploadImageClick", ex);
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private void UploadFileClick(object sender, EventArgs ea)
        {
            try
            {
                if (_fileUpload.HasFile)
                {
                    var path = Bloget.Page.MapPath(Bloget.Blog.ImageFolder);
                    path = Path.Combine(path, _fileUpload.FileName);
                    _fileUpload.SaveAs(path);

                    const int kiloByte = 1024;
                    const int megaByte = kiloByte*kiloByte;
                    var length = _fileUpload.PostedFile.ContentLength;

                    var fileLink =
                        string.Format(CultureInfo.CurrentCulture, @"<a href=""{0}"">{1} ({2:#.##} {3})</a>",
                                      Bloget.Blog.ImageUrl + _fileUpload.FileName,
                                      _fileUpload.FileName,
                                      (length > megaByte) ? (((double) length)/megaByte) : (((double) length)/kiloByte),
                                      (length > megaByte) ? Resources.EditViewMegabyte : Resources.EditViewKilobyte);

                    _text.Text += fileLink;
                }
            }

            catch (Exception ex)
            {
                Log.Exception(Bloget, "UploadFileClick", ex);
            }
        }
    }
}